package com.zenithmind.coding.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DockerClientBuilder;
import com.google.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.FormatterException;
import com.zenithmind.coding.pojo.dto.CodeRunDTO;
import com.zenithmind.coding.pojo.vo.CodeRunResultVO;
import com.zenithmind.coding.service.CodeExecutionService;
import info.debatty.java.stringsimilarity.Cosine;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 代码执行服务实现类
 * 
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CodeExecutionServiceImpl implements CodeExecutionService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;

    @Value("${coding.execution.enabled:true}")
    private Boolean executionEnabled;

    @Value("${coding.execution.timeout:30}")
    private Integer defaultTimeout;

    @Value("${coding.execution.memory-limit:256}")
    private Integer defaultMemoryLimit;

    @Value("${coding.execution.sandbox-mode:docker}")
    private String sandboxMode;

    @Value("${coding.storage.code-path:./data/coding/codes}")
    private String codePath;

    // 支持的编程语言
    private static final String[] SUPPORTED_LANGUAGES = {
        "java", "python", "cpp", "c", "javascript", "go", "rust", "csharp"
    };

    // 语言配置映射
    private static final Map<String, LanguageConfig> LANGUAGE_CONFIGS = new HashMap<>();

    // 运行中的任务
    private final Map<String, CompletableFuture<CodeRunResultVO>> runningTasks = new ConcurrentHashMap<>();

    static {
        // Java配置
        LANGUAGE_CONFIGS.put("java", new LanguageConfig(
            "openjdk:17-alpine",
            "Main.java",
            "javac Main.java",
            "java Main",
            ".java"
        ));

        // Python配置
        LANGUAGE_CONFIGS.put("python", new LanguageConfig(
            "python:3.11-alpine",
            "main.py",
            "",
            "python main.py",
            ".py"
        ));

        // C++配置
        LANGUAGE_CONFIGS.put("cpp", new LanguageConfig(
            "gcc:latest",
            "main.cpp",
            "g++ -o main main.cpp",
            "./main",
            ".cpp"
        ));

        // C配置
        LANGUAGE_CONFIGS.put("c", new LanguageConfig(
            "gcc:latest",
            "main.c",
            "gcc -o main main.c",
            "./main",
            ".c"
        ));

        // JavaScript配置
        LANGUAGE_CONFIGS.put("javascript", new LanguageConfig(
            "node:18-alpine",
            "main.js",
            "",
            "node main.js",
            ".js"
        ));

        // Go配置
        LANGUAGE_CONFIGS.put("go", new LanguageConfig(
            "golang:1.21-alpine",
            "main.go",
            "go build -o main main.go",
            "./main",
            ".go"
        ));
    }

    @Override
    public CodeRunResultVO runCode(CodeRunDTO codeRunDTO) {
        if (!executionEnabled) {
            return createErrorResult("代码执行功能已禁用", null);
        }

        if (!isLanguageSupported(codeRunDTO.getLanguage())) {
            return createErrorResult("不支持的编程语言: " + codeRunDTO.getLanguage(), null);
        }

        String runId = UUID.randomUUID().toString();
        log.info("开始执行代码，运行ID: {}, 语言: {}", runId, codeRunDTO.getLanguage());

        try {
            CodeRunResultVO result = executeCode(runId, codeRunDTO);
            
            // 缓存结果
            redisTemplate.opsForValue().set("code_run_result:" + runId, result, 1, TimeUnit.HOURS);
            
            return result;
        } catch (Exception e) {
            log.error("代码执行异常", e);
            return createErrorResult("代码执行异常: " + e.getMessage(), runId);
        }
    }

    @Override
    public String runCodeAsync(CodeRunDTO codeRunDTO) {
        if (!executionEnabled) {
            throw new RuntimeException("代码执行功能已禁用");
        }

        if (!isLanguageSupported(codeRunDTO.getLanguage())) {
            throw new RuntimeException("不支持的编程语言: " + codeRunDTO.getLanguage());
        }

        String runId = UUID.randomUUID().toString();
        log.info("开始异步执行代码，运行ID: {}, 语言: {}", runId, codeRunDTO.getLanguage());

        // 创建异步任务
        CompletableFuture<CodeRunResultVO> future = CompletableFuture.supplyAsync(() -> {
            try {
                return executeCode(runId, codeRunDTO);
            } catch (Exception e) {
                log.error("异步代码执行异常", e);
                return createErrorResult("代码执行异常: " + e.getMessage(), runId);
            }
        });

        // 保存任务引用
        runningTasks.put(runId, future);

        // 任务完成后缓存结果并清理
        future.whenComplete((result, throwable) -> {
            runningTasks.remove(runId);
            if (result != null) {
                redisTemplate.opsForValue().set("code_run_result:" + runId, result, 1, TimeUnit.HOURS);
            }
        });

        return runId;
    }

    @Override
    public CodeRunResultVO getRunResult(String runId) {
        // 先检查是否还在运行中
        CompletableFuture<CodeRunResultVO> runningTask = runningTasks.get(runId);
        if (runningTask != null) {
            if (runningTask.isDone()) {
                try {
                    return runningTask.get();
                } catch (Exception e) {
                    log.error("获取运行结果异常", e);
                    return createErrorResult("获取运行结果异常: " + e.getMessage(), runId);
                }
            } else {
                // 还在运行中
                CodeRunResultVO result = new CodeRunResultVO();
                result.setRunId(runId);
                result.setStatus(1); // 运行中
                result.setStatusMessage("代码正在运行中...");
                return result;
            }
        }

        // 从缓存获取结果
        CodeRunResultVO result = (CodeRunResultVO) redisTemplate.opsForValue().get("code_run_result:" + runId);
        if (result == null) {
            return createErrorResult("运行结果不存在或已过期", runId);
        }

        return result;
    }

    @Override
    public Boolean stopCodeRun(String runId) {
        CompletableFuture<CodeRunResultVO> runningTask = runningTasks.get(runId);
        if (runningTask != null) {
            boolean cancelled = runningTask.cancel(true);
            if (cancelled) {
                runningTasks.remove(runId);
                log.info("已停止代码运行: {}", runId);
            }
            return cancelled;
        }
        return false;
    }

    @Override
    public Boolean isLanguageSupported(String language) {
        return Arrays.asList(SUPPORTED_LANGUAGES).contains(language.toLowerCase());
    }

    @Override
    public String[] getSupportedLanguages() {
        return SUPPORTED_LANGUAGES.clone();
    }

    @Override
    public String formatCode(String language, String sourceCode) {
        try {
            switch (language.toLowerCase()) {
                case "java":
                    return new Formatter().formatSource(sourceCode);
                case "python":
                    // Python代码格式化（简单实现）
                    return formatPythonCode(sourceCode);
                default:
                    return sourceCode; // 其他语言暂不支持格式化
            }
        } catch (FormatterException e) {
            log.error("代码格式化失败", e);
            return sourceCode;
        }
    }

    @Override
    public CodeRunResultVO.CodeQualityAnalysis analyzeCodeQuality(String language, String sourceCode) {
        CodeRunResultVO.CodeQualityAnalysis analysis = new CodeRunResultVO.CodeQualityAnalysis();
        
        // 基本统计
        String[] lines = sourceCode.split("\n");
        analysis.setLineCount(lines.length);
        
        int effectiveLines = 0;
        int commentLines = 0;
        int blankLines = 0;
        
        for (String line : lines) {
            String trimmedLine = line.trim();
            if (trimmedLine.isEmpty()) {
                blankLines++;
            } else if (isCommentLine(language, trimmedLine)) {
                commentLines++;
            } else {
                effectiveLines++;
            }
        }
        
        analysis.setEffectiveLineCount(effectiveLines);
        analysis.setCommentLineCount(commentLines);
        analysis.setBlankLineCount(blankLines);
        
        // 圈复杂度计算（简化版）
        analysis.setCyclomaticComplexity(calculateCyclomaticComplexity(language, sourceCode));
        
        // 质量评分计算
        int qualityScore = calculateQualityScore(analysis);
        analysis.setQualityScore(qualityScore);
        analysis.setStyleScore(calculateStyleScore(language, sourceCode));
        analysis.setReadabilityScore(calculateReadabilityScore(analysis));
        
        // 生成建议
        analysis.setSuggestions(generateSuggestions(analysis));
        
        return analysis;
    }

    @Override
    public Double detectCodeSimilarity(String language, String sourceCode1, String sourceCode2) {
        try {
            // 预处理代码（去除注释、空行等）
            String cleanCode1 = preprocessCode(language, sourceCode1);
            String cleanCode2 = preprocessCode(language, sourceCode2);
            
            // 使用余弦相似度算法
            Cosine cosine = new Cosine();
            return cosine.similarity(cleanCode1, cleanCode2);
        } catch (Exception e) {
            log.error("代码相似度检测失败", e);
            return 0.0;
        }
    }

    /**
     * 执行代码
     */
    private CodeRunResultVO executeCode(String runId, CodeRunDTO codeRunDTO) {
        CodeRunResultVO result = new CodeRunResultVO();
        result.setRunId(runId);
        result.setLanguage(codeRunDTO.getLanguage());
        result.setSourceCode(codeRunDTO.getSourceCode());
        result.setInput(codeRunDTO.getInput());
        result.setTimeLimit(codeRunDTO.getTimeLimit());
        result.setMemoryLimit(codeRunDTO.getMemoryLimit());

        try {
            if ("docker".equals(sandboxMode)) {
                return executeInDocker(result, codeRunDTO);
            } else {
                return executeLocally(result, codeRunDTO);
            }
        } catch (Exception e) {
            log.error("代码执行失败", e);
            result.setStatus(8); // 系统错误
            result.setStatusMessage("系统错误");
            result.setErrorInfo(e.getMessage());
            return result;
        }
    }

    /**
     * 在Docker中执行代码
     */
    private CodeRunResultVO executeInDocker(CodeRunResultVO result, CodeRunDTO codeRunDTO) {
        LanguageConfig config = LANGUAGE_CONFIGS.get(codeRunDTO.getLanguage());
        if (config == null) {
            result.setStatus(8);
            result.setStatusMessage("不支持的语言");
            return result;
        }

        try {
            // 创建临时目录
            Path tempDir = Files.createTempDirectory("code_run_" + result.getRunId());
            Path codeFile = tempDir.resolve(config.getFileName());
            
            // 写入代码文件
            Files.write(codeFile, codeRunDTO.getSourceCode().getBytes());
            
            // 创建输入文件
            if (StringUtils.hasText(codeRunDTO.getInput())) {
                Path inputFile = tempDir.resolve("input.txt");
                Files.write(inputFile, codeRunDTO.getInput().getBytes());
            }

            // 使用Docker执行
            DockerClient dockerClient = DockerClientBuilder.getInstance().build();
            
            // 创建容器
            CreateContainerResponse container = dockerClient.createContainerCmd(config.getDockerImage())
                .withHostConfig(HostConfig.newHostConfig()
                    .withBinds(new Bind(tempDir.toString(), new Volume("/workspace")))
                    .withMemory((long) codeRunDTO.getMemoryLimit() * 1024) // KB to bytes
                    .withCpuShares(512))
                .withWorkingDir("/workspace")
                .withNetworkMode("none") // 禁用网络
                .exec();

            String containerId = container.getId();
            
            try {
                // 启动容器
                dockerClient.startContainerCmd(containerId).exec();
                
                LocalDateTime startTime = LocalDateTime.now();
                result.setRunStartTime(startTime);
                
                // 编译（如果需要）
                if (StringUtils.hasText(config.getCompileCommand())) {
                    result.setCompileStartTime(LocalDateTime.now());
                    
                    ExecCreateCmdResponse compileExec = dockerClient.execCreateCmd(containerId)
                        .withCmd("sh", "-c", config.getCompileCommand())
                        .withAttachStdout(true)
                        .withAttachStderr(true)
                        .exec();
                    
                    // 执行编译命令并获取结果
                    // 这里简化处理，实际应该使用回调获取输出
                    
                    result.setCompileEndTime(LocalDateTime.now());
                    result.setCompileDuration(java.time.Duration.between(result.getCompileStartTime(), result.getCompileEndTime()).toMillis());
                }
                
                // 运行程序
                String runCommand = config.getRunCommand();
                if (StringUtils.hasText(codeRunDTO.getInput())) {
                    runCommand = runCommand + " < input.txt";
                }
                
                ExecCreateCmdResponse runExec = dockerClient.execCreateCmd(containerId)
                    .withCmd("sh", "-c", runCommand)
                    .withAttachStdout(true)
                    .withAttachStderr(true)
                    .exec();
                
                // 这里应该实现超时控制和输出捕获
                // 简化处理
                result.setStatus(2); // 运行成功
                result.setStatusMessage("运行成功");
                result.setOutput("Hello World!"); // 示例输出
                result.setRunTime(100); // 示例运行时间
                result.setRunMemory(1024); // 示例内存使用
                
                result.setRunEndTime(LocalDateTime.now());
                result.setRunDuration(java.time.Duration.between(result.getRunStartTime(), result.getRunEndTime()).toMillis());
                
            } finally {
                // 清理容器
                try {
                    dockerClient.removeContainerCmd(containerId).withForce(true).exec();
                } catch (Exception e) {
                    log.warn("清理Docker容器失败: {}", containerId, e);
                }
            }
            
            // 清理临时文件
            Files.deleteIfExists(codeFile);
            Files.deleteIfExists(tempDir);
            
        } catch (Exception e) {
            log.error("Docker执行失败", e);
            result.setStatus(8);
            result.setStatusMessage("系统错误");
            result.setErrorInfo(e.getMessage());
        }

        return result;
    }

    /**
     * 本地执行代码（简化版，仅用于演示）
     */
    private CodeRunResultVO executeLocally(CodeRunResultVO result, CodeRunDTO codeRunDTO) {
        // 本地执行存在安全风险，这里仅作演示
        result.setStatus(2);
        result.setStatusMessage("运行成功");
        result.setOutput("Hello World! (本地执行)");
        result.setRunTime(50);
        result.setRunMemory(512);
        result.setRunStartTime(LocalDateTime.now());
        result.setRunEndTime(LocalDateTime.now());
        result.setRunDuration(50L);
        
        return result;
    }

    /**
     * 创建错误结果
     */
    private CodeRunResultVO createErrorResult(String errorMessage, String runId) {
        CodeRunResultVO result = new CodeRunResultVO();
        result.setRunId(runId);
        result.setStatus(8); // 系统错误
        result.setStatusMessage("系统错误");
        result.setErrorInfo(errorMessage);
        return result;
    }

    /**
     * 格式化Python代码（简化版）
     */
    private String formatPythonCode(String sourceCode) {
        // 简单的Python代码格式化
        String[] lines = sourceCode.split("\n");
        StringBuilder formatted = new StringBuilder();
        int indentLevel = 0;
        
        for (String line : lines) {
            String trimmed = line.trim();
            if (trimmed.isEmpty()) {
                formatted.append("\n");
                continue;
            }
            
            // 简单的缩进处理
            if (trimmed.endsWith(":")) {
                formatted.append("    ".repeat(indentLevel)).append(trimmed).append("\n");
                indentLevel++;
            } else {
                formatted.append("    ".repeat(indentLevel)).append(trimmed).append("\n");
            }
        }
        
        return formatted.toString();
    }

    /**
     * 判断是否为注释行
     */
    private boolean isCommentLine(String language, String line) {
        switch (language.toLowerCase()) {
            case "java":
            case "cpp":
            case "c":
            case "javascript":
                return line.startsWith("//") || line.startsWith("/*") || line.startsWith("*");
            case "python":
                return line.startsWith("#");
            default:
                return false;
        }
    }

    /**
     * 计算圈复杂度（简化版）
     */
    private Integer calculateCyclomaticComplexity(String language, String sourceCode) {
        int complexity = 1; // 基础复杂度
        
        // 简单的关键字计数
        String[] keywords = {"if", "else", "while", "for", "switch", "case", "catch", "&&", "||"};
        
        for (String keyword : keywords) {
            Pattern pattern = Pattern.compile("\\b" + keyword + "\\b");
            Matcher matcher = pattern.matcher(sourceCode);
            while (matcher.find()) {
                complexity++;
            }
        }
        
        return complexity;
    }

    /**
     * 计算质量评分
     */
    private Integer calculateQualityScore(CodeRunResultVO.CodeQualityAnalysis analysis) {
        int score = 100;
        
        // 根据注释率调整分数
        double commentRate = (double) analysis.getCommentLineCount() / analysis.getLineCount();
        if (commentRate < 0.1) {
            score -= 20; // 注释太少
        } else if (commentRate > 0.5) {
            score -= 10; // 注释太多
        }
        
        // 根据圈复杂度调整分数
        if (analysis.getCyclomaticComplexity() > 10) {
            score -= 30;
        } else if (analysis.getCyclomaticComplexity() > 5) {
            score -= 15;
        }
        
        return Math.max(0, score);
    }

    /**
     * 计算代码风格评分
     */
    private Integer calculateStyleScore(String language, String sourceCode) {
        // 简化的代码风格评分
        return 85; // 示例分数
    }

    /**
     * 计算可读性评分
     */
    private Integer calculateReadabilityScore(CodeRunResultVO.CodeQualityAnalysis analysis) {
        int score = 100;
        
        // 根据平均行长度调整
        if (analysis.getEffectiveLineCount() > 0) {
            // 简化计算
            score = Math.max(60, 100 - analysis.getCyclomaticComplexity() * 2);
        }
        
        return score;
    }

    /**
     * 生成代码改进建议
     */
    private List<String> generateSuggestions(CodeRunResultVO.CodeQualityAnalysis analysis) {
        List<String> suggestions = new ArrayList<>();
        
        if (analysis.getCommentLineCount() == 0) {
            suggestions.add("建议添加适当的注释来提高代码可读性");
        }
        
        if (analysis.getCyclomaticComplexity() > 10) {
            suggestions.add("代码复杂度较高，建议拆分为更小的函数");
        }
        
        if (analysis.getQualityScore() < 70) {
            suggestions.add("代码质量有待提升，建议遵循编码规范");
        }
        
        return suggestions;
    }

    /**
     * 预处理代码（去除注释、空行等）
     */
    private String preprocessCode(String language, String sourceCode) {
        String[] lines = sourceCode.split("\n");
        StringBuilder processed = new StringBuilder();
        
        for (String line : lines) {
            String trimmed = line.trim();
            if (!trimmed.isEmpty() && !isCommentLine(language, trimmed)) {
                processed.append(trimmed).append("\n");
            }
        }
        
        return processed.toString();
    }

    /**
     * 语言配置类
     */
    private static class LanguageConfig {
        private final String dockerImage;
        private final String fileName;
        private final String compileCommand;
        private final String runCommand;
        private final String fileExtension;

        public LanguageConfig(String dockerImage, String fileName, String compileCommand, String runCommand, String fileExtension) {
            this.dockerImage = dockerImage;
            this.fileName = fileName;
            this.compileCommand = compileCommand;
            this.runCommand = runCommand;
            this.fileExtension = fileExtension;
        }

        public String getDockerImage() { return dockerImage; }
        public String getFileName() { return fileName; }
        public String getCompileCommand() { return compileCommand; }
        public String getRunCommand() { return runCommand; }
        public String getFileExtension() { return fileExtension; }
    }
}
